package com.zh.common.socket

import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
import java.util.concurrent.TimeUnit
import android.os.Handler
import android.os.Looper.myLooper
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch


class ClientSocket private constructor() {

    private val TAG = "ClientSocket"
    private var isConnect = false
    private var scope: CoroutineScope? = null
    private var receiveMessage: IReceiveMessage? = null

    private var connectNum = 0
    private val MAX_NUM = Int.MAX_VALUE // 最大重连数
    private val MILLIS = 1500L // 重连间隔时间，毫秒
    private var sendTime = 0L //心跳包发送时间计时
    private val mHandler = myLooper()?.let { Handler(it) } // 发送心跳包
    private val HEART_BEAT_RATE = 40 * 1000L // 每隔40秒发送一次心跳包，检测连接没有断开

    private var WSURL = "你的Websocket地址"
    private val WSHEART = "ok-" // 心跳包

    companion object {
        @JvmStatic
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ClientSocket() }
    }

    private val mClient by lazy {
        OkHttpClient.Builder()
            .readTimeout(5, TimeUnit.SECONDS) //设置读取超时时间
            .writeTimeout(5, TimeUnit.SECONDS) //设置写的超时时间
            .connectTimeout(5, TimeUnit.SECONDS) //设置连接超时时间
            .build()
    }

    private var mSocket: WebSocket? = null

    private fun createRequest(): Request {
        return Request.Builder().get().url(WSURL).build()
    }

    /**
     *
     */
    fun init(scope: CoroutineScope, url: String, receive: IReceiveMessage) {
        this.scope = scope
        WSURL = url
        receiveMessage = receive
        connect()
    }

    /**
     * 连接
     */
    fun connect() {
        if (isConnect()) {
            Log.i(TAG, "WebSocket 已经连接！")
            return
        }
        mSocket = mClient.newWebSocket(createRequest(), createListener())
    }

    /**
     * 重连
     */
    fun reconnect() {
        if (connectNum <= MAX_NUM) {
            try {
                scope?.launch {
                    delay(MILLIS)
                    connect()
                    connectNum++
                }
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        } else {
            Log.i(TAG, "reconnect over $MAX_NUM, please check url or network")
        }
    }

    /**
     * 是否连接
     */
    fun isConnect(): Boolean {
        return mSocket != null && isConnect
    }

    // 发送心跳包
    private fun heartBeatRunnable() = object : Runnable {
        override fun run() {
            mHandler?.removeCallbacksAndMessages(null)
            if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
                sendTime = System.currentTimeMillis()
                val isSend = sendMessage(WSHEART)
                Log.i(TAG, "心跳是否发送成功$isSend")
            }
            mHandler?.postDelayed(this, HEART_BEAT_RATE) //每隔一定的时间，对长连接进行一次心跳检测
        }
    }

    /**
     * 发送消息
     *
     * @param text 字符串
     * @return boolean
     */
    fun sendMessage(text: String): Boolean {
        if (!isConnect()) return false
        return mSocket?.send(text) ?: false
    }

    /**
     * 发送消息
     *
     * @param byteString 字符集
     * @return boolean
     */
    fun sendMessage(byteString: ByteString): Boolean {
        if (!isConnect()) return false
        return mSocket?.send(byteString) ?: false
    }

    /**
     * 关闭连接
     */
    fun close() {
        if (isConnect()) {
            scope?.cancel()
            mSocket?.cancel()
            mSocket?.close(1001, "客户端主动关闭连接");
        }
        mHandler?.removeCallbacksAndMessages(null)
    }

    private fun createListener(): WebSocketListener {
        return object : WebSocketListener() {

            override fun onOpen(webSocket: WebSocket, response: Response) {
                super.onOpen(webSocket, response)
                Log.i(TAG, "WebSocket 打开:$response")
                isConnect = response.code == 101
                if (!isConnect) {
                    reconnect()
                } else {
                    Log.i(TAG, "WebSocket 连接成功")
                    receiveMessage?.onConnectSuccess()
                    mHandler?.postDelayed(heartBeatRunnable(), HEART_BEAT_RATE)
                }
            }

            override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
                super.onMessage(webSocket, bytes)
                receiveMessage?.onMessage(bytes)
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                super.onMessage(webSocket, text)
                receiveMessage?.onMessage(text)
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosing(webSocket, code, reason)
                isConnect = false
                receiveMessage?.onClose()
                mHandler?.removeCallbacksAndMessages(null)
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                super.onClosed(webSocket, code, reason)
                isConnect = false
                receiveMessage?.onClose()
                mHandler?.removeCallbacksAndMessages(null)
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                super.onFailure(webSocket, t, response)
                if (response != null) {
                    Log.i(TAG, "WebSocket 连接失败：" + response.message)
                }
                Log.i(TAG, "WebSocket 连接失败异常原因：" + t.message)
                isConnect = false
                mHandler?.removeCallbacksAndMessages(null)
                receiveMessage?.onConnectFailed()
                if (!t.message.isNullOrEmpty() && !t.message.equals("Socket closed")) {
                    reconnect()
                }
            }
        }
    }
}